home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
edit
/
elv18src.zip
/
cmd1.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-01-10
|
39KB
|
1,976 lines
/* cmd1.c */
/* Author:
* Steve Kirkendall
* 14407 SW Teal Blvd. #C
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*/
/* This file contains some of the EX commands - mostly ones that deal with
* files, options, etc. -- anything except text.
*/
#include "config.h"
#include "ctype.h"
#include "vi.h"
#include "regexp.h"
#ifdef INTERNAL_TAGS
# ifdef __STDC__
# include "string.h"
# else
extern char *strrchr();
# endif
#endif
#ifndef NO_TAGSTACK
/* These describe the current state of the tag related commands */
#define MAXTAGS 15
struct Tag_item {
MARK tag_mark;
char *tag_file;
};
static struct Tag_item tag_stack[MAXTAGS];
static int curr_tag = -1;
#endif /* !NO_TAGSTACK */
#ifdef DEBUG
/* print the selected lines with info on the blocks */
/*ARGSUSED*/
void cmd_debug(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
REG char *scan;
REG long l;
REG int i;
int len;
/* scan lnum[] to determine which block its in */
l = markline(frommark);
for (i = 1; l > lnum[i]; i++)
{
}
do
{
/* fetch text of the block containing that line */
scan = blkget(i)->c;
/* calculate its length */
if (scan[BLKSIZE - 1])
{
len = BLKSIZE;
}
else
{
len = strlen(scan);
}
/* print block stats */
msg("##### hdr[%d]=%d, lnum[%d-1]=%ld, lnum[%d]=%ld (%ld lines)",
i, hdr.n[i], i, lnum[i-1], i, lnum[i], lnum[i] - lnum[i - 1]);
msg("##### len=%d, buf=0x%lx, %sdirty",
len, scan, ((int *)scan)[MAXBLKS + 1] ? "" : "not ");
if (bang)
{
while (--len >= 0)
{
addch(*scan);
scan++;
}
}
exrefresh();
/* next block */
i++;
} while (i < MAXBLKS && lnum[i] && lnum[i - 1] < markline(tomark));
}
/* This function checks a lot of conditions to make sure they aren't screwy */
/*ARGSUSED*/
void cmd_validate(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
char *scan;
int i;
int nlcnt; /* used to count newlines */
int len; /* counts non-NUL characters */
/* check lnum[0] */
if (lnum[0] != 0L)
{
msg("lnum[0] = %ld", lnum[0]);
}
/* check each block */
for (i = 1; lnum[i] <= nlines; i++)
{
scan = blkget(i)->c;
if (scan[BLKSIZE - 1])
{
msg("block %d has no NUL at the end", i);
}
else
{
for (nlcnt = len = 0; *scan; scan++, len++)
{
if (*scan == '\n')
{
nlcnt++;
}
}
if (scan[-1] != '\n')
{
msg("block %d doesn't end with '\\n' (length %d)", i, len);
}
if (bang || nlcnt != lnum[i] - lnum[i - 1])
{
msg("block %d (line %ld?) has %d lines, but should have %ld",
i, lnum[i - 1] + 1L, nlcnt, lnum[i] - lnum[i - 1]);
}
}
exrefresh();
}
/* check lnum again */
if (lnum[i] != INFINITY)
{
msg("hdr.n[%d] = %d, but lnum[%d] = %ld",
i, hdr.n[i], i, lnum[i]);
}
msg("# = \"%s\", %% = \"%s\"", prevorig, origname);
msg("V_from=%ld.%d, cursor=%ld.%d", markline(V_from), markidx(V_from), markline(cursor), markidx(cursor));
}
#endif /* DEBUG */
/*ARGSUSED*/
void cmd_mark(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
/* validate the name of the mark */
if (*extra == '"')
{
extra++;
}
/* valid mark names are lowercase ascii characters */
if (!isascii(*extra) || !islower(*extra) || extra[1])
{
msg("Invalid mark name");
return;
}
mark[*extra - 'a'] = tomark;
}
/*ARGSUSED*/
void cmd_write(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
int fd;
int append; /* boolean: write in "append" mode? */
REG long l;
REG char *scan;
REG int i;
/* if writing to a filter, then let filter() handle it */
if (*extra == '!')
{
filter(frommark, tomark, extra + 1, FALSE);
return;
}
/* if all lines are to be written, use tmpsave() */
if (frommark == MARK_FIRST && tomark == MARK_LAST && cmd == CMD_WRITE)
{
tmpsave(extra, bang);
return;
}
/* see if we're going to do this in append mode or not */
append = FALSE;
if (extra[0] == '>' && extra[1] == '>')
{
extra += 2;
append = TRUE;
}
/* either the file must not exist, or we must have a ! or be appending */
if (*extra && access(extra, 0) == 0 && !bang && !append)
{
msg("File already exists - Use :w! to overwrite");
return;
}
/* else do it line-by-line, like cmd_print() */
if (append)
{
#ifdef O_APPEND
fd = open(extra, O_WRONLY|O_APPEND);
#else
fd = open(extra, O_WRONLY);
if (fd >= 0)
{
lseek(fd, 0L, 2);
}
#endif
}
else
{
fd = -1; /* so we know the file isn't open yet */
}
if (fd < 0)
{
fd = creat(extra, FILEPERMS);
if (fd < 0)
{
msg("Can't write to \"%s\"", extra);
return;
}
}
for (l = markline(frommark); l <= markline(tomark); l++)
{
/* get the next line */
scan = fetchline(l);
i = strlen(scan);
scan[i++] = '\n';
/* print the line */
if (twrite(fd, scan, i) < i)
{
msg("Write failed");
break;
}
}
rptlines = markline(tomark) - markline(frommark) + 1;
rptlabel = "written";
#if MSDOS
if (*o_controlz)
{
write(fd, "\032", 1);
}
#endif
close(fd);
}
/*ARGSUSED*/
void cmd_shell(frommark, tomark, cmd, bang, extra)
MARK frommark, tomark;
CMD cmd;
int bang;
char *extra;
{
static char prevextra[132];
/* special case: ":sh" means ":!sh" */
if (cmd == CMD_SHELL)
{
extra = o_shell;
frommark = tomark = 0L;
}
/* if already did one or more shell commands, need extra newline to
* avoid overwriting user's command string */
if (mode == MODE_COLON)
{
addch('\n');
}
/* if extra is "!", substitute previous command */
if (*extra == '!')
{
if (!*prevextra)
{
msg("No previous shell command to substitute for '!'");
return;
}
strcat(prevextra, extra + 1);
extra = prevextra;
}
else if (cmd == CMD_BANG && (unsigned)strlen(extra) < sizeof(prevextra) - 1)
{
strcpy(prevextra, extra);
}
/* warn the user if the file hasn't been saved yet */
if (*o_warn && tstflag(file, MODIFIED))
{
if (mode == MODE_VI)
{
mode = MODE_COLON;
}
msg("Warning: \"%s\" has been modified but not yet saved", origname);
}
/* if no lines were specified, just run the command */
suspend_curses();
if (frommark == 0L)
{
system(extra);
}
else /* pipe lines from the file through the command */
{
filter(frommark, tomark, extra, TRUE);
}
/* resume curses quietly for MODE_EX, but noisily otherwise */
resume_curses(mode == MODE_EX);
}
/*ARGSUSED*/
void cmd_global(frommark, tomark, cmd, bang, extra)
MARK frommark, tomark;
CMD cmd;
int bang;
char *extra; /* rest of the command line */
{
char *cmdptr; /* the command from the command line */
char cmdln[100]; /* copy of the command from the command line */
char *line; /* a line from the file */
long l; /* used as a counter to move through lines */
long lqty; /* quantity of lines to be scanned */
long nchanged; /* number of lines changed */
regexp *re; /* the compiled search expression */
/* can't nest global commands */
if (doingglobal)
{
msg("Can't nest global commands.");
rptlines = -1L;
return;
}
/* ":g! ..." is the same as ":v ..." */
if (bang)
{
cmd = CMD_VGLOBAL;
}
/* make sure we got a search pattern */
if (!*extra)
{
msg("Usage: %c /regular expression/ command", cmd == CMD_GLOBAL ? 'g' : 'v');
return;
}
/* parse & compile the search pattern */
cmdptr = parseptrn(extra);
#if 0
if (!extra[1])
{
msg("Can't use empty regular expression with '%c' command", cmd == CMD_GLOBAL ? 'g' : 'v');
return;
}
#endif
re = regcomp(extra + 1);
if (!re)
{
/* regcomp found & described an error */
return;
}
/* for each line in the range */
doingglobal = TRUE;
ChangeText
{
/* NOTE: we have to go through the lines in a forward order,
* otherwise "g/re/p" would look funny. *BUT* for "g/re/d"
* to work, simply adding 1 to the line# on each loop won't
* work. The solution: count lines relative to the end of
* the file. Think about it.
*/
for (l = nlines - markline(frommark),
lqty = markline(tomark) - markline(frommark) + 1L,
nchanged = 0L;
lqty > 0 && nlines - l >= 0 && nchanged >= 0L;
l--, lqty--)